#ifndef _ECMFS_API_H_
#define _ECMFS_API_H_
#include "ecmfs_cmn.h"

#define PROCEED 0xABCD
#define STOP -1
#define MAX_OPTS 100  /* Maximum length of the argstr string passed to
                       * up_parse_arguments */



typedef struct _sock_ctx SOCK_CTX;
struct _sock_ctx {
    /* server socket */
	int sock;
};


typedef struct _commctx COMMCTX;
struct _commctx {
  SOCK_CTX* sock_ctx; /*  context that contains socket */
  void* sec_ctx; /* upper layer can store its context here */
  /*  Function pointers to network functions layer */
  int (*receive)(COMMCTX*, char*, int); 
  int (*send)(COMMCTX*, char*, int);
};
#define MAGIC_NUM 19977991

typedef enum node_type_ {
    NODE_NONE = 0,
    NODE_CLIENT,
    NODE_EDGE,
    NODE_CORE,
    NODE_MASTER
} node_type_t;

typedef enum client_op_ {
    CLIENT_OP_NONE = 0,
    CLIENT_OP_HELLO,
    CLIENT_OP_ADDUSER,
    CLIENT_OP_REMUSER,
    CLIENT_OP_MOUNT,
    CLIENT_OP_UNMOUNT,
    CLIENT_OP_REQ_PUB_KEY,
} client_op_t;

typedef enum master_op_ {
    MASTER_OP_NONE = 0,
    MASTER_OP_RESPONSE,
    MASTER_OP_NOTIFICATION,
    MASTER_OP_USERUPDATE,
    MASTER_OP_NODEUPDATE,
    MASTER_OP_SESSIONUPDATE,
    MASTER_OP_FAILOVER
} master_op_t;

typedef struct session_aes_key_ {
    char user_id[32];
    char user_ip[32];
    int  user_port;
    char edge_name[32];    
    char edge_ip[32];
    int  edge_port;
    unsigned char key[AES_KEYLEN/8];
    unsigned char iv[AES_KEYLEN/8];
} session_aes_key_t;

typedef struct ecmfs_message_ {
    int magic_num; /*19977991*/
    int to ;
    int from ; /* 1 - client
                   2 - edge
                   3 - core
                   4 - master
                 */
    int type;
                /* client: 1 -- add_user
                           2 -- remove_user
                           3 -- start_session
                           4 -- end_session
                   edge:   1 -- filegroup_sync
                           2 -- file_sync
                           3 -- report_error
                   core:   1 -- file_sync
                           2 -- report_error
                   master: 1 -- user_update
                           2 -- node_update
                           3 -- start_session
                           4 -- notify_error
                           5 -- failover_msg
                 */
     int  extra;
     int  message_len;
     char message[1];
} ecmfs_message_t;

#define MAX_PUB_KEY_LEN 2048

typedef struct ecmfs_add_user_ {
    char user_id[32];
    int  user_pub_key_len;
    unsigned char user_pub_key[2048];
} ecmfs_add_user_t;


typedef enum server_state_ {
    SERVER_STATE_UNKNOWN=0,
    SERVER_STATE_INITIALIZING,    
    SERVER_STATE_READY,
    SERVER_STATE_EDGE_READY,
    SERVER_STATE_CORE_READY,
    SERVER_STATE_INTERNAL_ERROR
}server_state_t;
typedef enum server_resp_ {
    SERVER_RESP_UNKNOWN=0,
    SERVER_RESP_HELLO,
    SERVER_RESP_WHOAREYOU,
    SERVER_RESP_SENDING_PUBKEY,
    SERVER_RESP_DONE,  
    SERVER_RESP_MOUNT_OK,     
    SERVER_RESP_ERROR,
    SERVER_NOTIFY_STATUS_UPDATE, 
    SERVER_NOTIFY_SESSION_UPDATE,
    SERVER_RESP_INTERNAL_ERROR
}server_resp_t;

typedef struct node_info_ {
    char node_name[32];
    node_type_t node_type;
    char node_ip[32];    
    int  node_port;
    int  node_pub_key_len;
    unsigned char node_pub_key[2048];
}node_info_t;

typedef struct ecmfs_runtime_state_ {
    server_state_t state;
    node_info_t info;
} ecmfs_runtime_state_t;

typedef struct ecmfs_client_master_response_ {
    server_state_t state;
    server_resp_t resp;
    int more;
    int msg_len;
    char msg[1]; 
} ecmfs_server_response_t;

bool_ecmfs client_handle_client_message(ecmfs_message_t *msg, int *more);
bool_ecmfs client_handle_edge_message(ecmfs_message_t *msg, int *more);
bool_ecmfs client_handle_core_message(ecmfs_message_t *msg, int *more);
bool_ecmfs client_handle_master_message(ecmfs_message_t *msg, int *more);

void client_handle_message(unsigned char *buffer,
    int bufsize, int *more) ; 
int receive_server_response(int sockfd,unsigned char **buffer,
    int *buff_len);
int client_send_message_to_master(ecmfs_message_t *msg, bool_ecmfs encrypted);
int start_mount_session(int argc,char **argv);
int send_ecmfs_request(client_op_t opcode, void *arg);
#endif
